﻿using eslib.DataRetrievalLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace eslib.nnp5.Matchers
{
    /*
    #### MicroFF协议说明

    1.以0xff 0x01为包头
    2.以0xff 0x02为包尾
    3.数据段中的0xff转义为0xff 0x00

    例:
        传输{0x41 0xff 0x42}

        转为MicroFF协议后:

        0xff 0x01 0x41 0xff 0x00 0x42 0xff 0x02

        -------------------------------------------------

        解包:
        去掉包头包尾
        0x41 0xff 0x00 0x42

        将数据中的 0xff 0x00 转为 0xff (遇到0xff,即忽略下一字节,因为现在数据中只有0xff 0x00一种组合)
        0x41 0xff 0x42
    */


    enum MicroFF_STATE
    {
        NONE = 0,        //未匹配到协议头
        HEAD_FF,       //匹配到包头0xff
        HEAD_RECV,       //接收状态(匹配到包头0x01后进入,或者遇到0xff 0x00后返回到接收状态)
        TAIL_FF,       //匹配到包尾0xff
                       //匹配到包尾0x01后将引发事件
    };



    /// <summary>
    /// 微型ff协议匹配器
    /// </summary>
    public class MicroFFMatcher
    {
        /// <summary>
        /// 
        /// </summary>
        public MicroFFMatcher()
        {
            reset();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="b"></param>
        public void inStream(byte b)
        {
            switch (ff_state)
            {
                case MicroFF_STATE.NONE:        //未匹配到包头
                    reset();        //重置stream
                    if (b == 0xff)
                    {
                        //包头也写入流
                        stream.write(b);
                        ff_state = MicroFF_STATE.HEAD_FF;        //匹配到包头0xff
                    }
                    break;

                case MicroFF_STATE.HEAD_FF:     //匹配到包头0xff
                    if (b == 0x01)
                    {
                        //包头也写入流
                        stream.write(b);
                        ff_state = MicroFF_STATE.HEAD_RECV;        //匹配到包头0x01
                    }
                    else ff_state = MicroFF_STATE.NONE;		//不匹配，重置
                    break;

                case MicroFF_STATE.HEAD_RECV:     //接收状态(匹配到包头0x01后进入,或者遇到0xff 0x00后返回到接收状态)
                    //写入流,所有数据写入流
                    stream.write(b);

                    if (b == 0xff)      //匹配到“可能的”包尾0(下一个可能是0x00)
                    {
                        ff_state = MicroFF_STATE.TAIL_FF;
                    }
                    break;

                case MicroFF_STATE.TAIL_FF:     //匹配到包尾0xff   
                    if (b == 0x02)//收到0x02,已完成	
                    {
                        //写入流
                        stream.write(b);

                        //引发事件
                        invokeEvent();

                        //重置状态机
                        ff_state = MicroFF_STATE.NONE;
                    }
                    else
                    {
                        //不是0x02，返回数据接收状态
                        //由于MicroFF协议中,在这一步只可能匹配到0x02或者0x00
                        //这里不将0x00写入流,自动完成0xff 0x00的转换
                        ff_state = MicroFF_STATE.HEAD_RECV;
                    }
                    break;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="buf"></param>
        public void inStream(byte[] buf)
        {
            for (int i = 0; i < buf.Length; i++) inStream(buf[i]);
        }



        /// <summary>
        /// 成功匹配后引发
        /// </summary>
        public event match_handle matchEvent;

        /// <summary>
        /// 重置
        /// </summary>
        public void reset()
        {
            ff_state = MicroFF_STATE.NONE;
            stream.clear();
        }


        /// <summary>
        /// 将data转换为微型FF协议数据格式,包括包头包尾
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static byte[] transInData(byte[] data)
        {
            List<byte> buf = new List<byte>();

            //包头
            buf.Add(0xff);
            buf.Add(0x01);

            foreach (var b in data)
            {
                buf.Add(b);

                //如果为0xff,转为0xff 0x00
                if (b == 0xff) buf.Add(0);
            }

            //包尾
            buf.Add(0xff);
            buf.Add(0x02);

            return buf.ToArray();
        }


        #region 内部实现


        internal stream stream { get; private set; } = new stream();

        /// <summary>
        /// ff协议状态机
        /// </summary>
        MicroFF_STATE ff_state = MicroFF_STATE.NONE;


        void invokeEvent()
        {
            byte[] buf = stream.get();
            matchEvent?.Invoke(buf.Skip(2).Take(buf.Length - 4).ToArray());     //去除包头包尾
        }
        #endregion

    }
}
